package org.feit.findword.view;

import java.util.ListIterator;

import org.feit.findword.R;
import org.feit.findword.Synchronizer;
import org.feit.findword.game.Game;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.graphics.Paint.Align;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

public class GameBoardView extends View implements Synchronizer.Event {
	protected static final String TAG = "GameBoardView";
	public static final int PADDING_C = 4;
	public static final int REDRAW_FREQ = 10;
	private int PADDING;

	private FingerTracker mFingerTracker;
	private Game mGame;
	private int mTimeRemaining;
	private int mRedrawCount;

	private int mWidth;
	private int mHeight;
	private int mGridSize;
	private float mBoxSize;

	private int mBoardWidth;
	private Bitmap mConsonant;
	private Bitmap mVocalLetter;
	private Bitmap mOver;
	private Paint mPaint;

	public long mHighlighted;
	private boolean mIsLoaded = false;

	public GameBoardView(Context context, Game game) {
		super(context);
		mGame = game;
		mBoardWidth = game.getBoard().getWidth();
		initView();
	}

	public GameBoardView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	public GameBoardView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public void setGame(Game game) {
		mGame = game;
		mBoardWidth = game.getBoard().getWidth();
		mFingerTracker = new FingerTracker(this, mGame);
		initView();
		mIsLoaded = true;
	}

	private void initView() {
		// mKeyboardTracker = new KeyboardTracker();
		Log.d(TAG, "width: " + mBoardWidth);
		if (mBoardWidth == 4) {
			mVocalLetter = BitmapFactory.decodeResource(getResources(),
					R.drawable.c2_4);
			mConsonant = BitmapFactory.decodeResource(getResources(),
					R.drawable.c1_4);
			mOver = BitmapFactory.decodeResource(getResources(),
					R.drawable.c3_4);
		}
		if (mBoardWidth == 5) {
			mVocalLetter = BitmapFactory.decodeResource(getResources(),
					R.drawable.c2_5);
			mConsonant = BitmapFactory.decodeResource(getResources(),
					R.drawable.c1_5);
			mOver = BitmapFactory.decodeResource(getResources(),
					R.drawable.c3_5);
		}
		if (mBoardWidth == 6) {
			mVocalLetter = BitmapFactory.decodeResource(getResources(),
					R.drawable.c2_6);
			mConsonant = BitmapFactory.decodeResource(getResources(),
					R.drawable.c1_6);
			mOver = BitmapFactory.decodeResource(getResources(),
					R.drawable.c3_6);
		}
		mTimeRemaining = 0;
		mRedrawCount = 1;

		mPaint = new Paint();
		mPaint.setTextAlign(Paint.Align.CENTER);
		mPaint.setAntiAlias(true);
		mPaint.setStrokeWidth(2);
		setFocusable(true);
		setKeepScreenOn(true);
		setFocusableInTouchMode(true);
		mIsLoaded = true;
	}

	private void setDimensions(int width, int height) {
		// Log.d(TAG,"setDimensions:"+w+","+h);

		mWidth = width;
		mHeight = height;
		PADDING = PADDING_C * mHeight / 100;

		mGridSize = Math.min(mWidth, mHeight) - 2 * PADDING;
		mBoxSize = ((float) mGridSize) / mBoardWidth;

		// Log.d(TAG,"gridsize:"+gridsize);

		if (mFingerTracker != null) {
			mFingerTracker.boundBoard(PADDING, PADDING, PADDING + mGridSize,
					PADDING + mGridSize);
		}
	}

	private void drawBoard(Canvas canvas) {
		// Draw round rectangle
		mPaint.setStrokeWidth(2);
		mPaint.setARGB(255, 0xff, 0xcc, 0xaa);
		canvas.drawRoundRect(new RectF(PADDING - 2, PADDING - 2, mGridSize
				+ PADDING + 2, mGridSize + PADDING + 2), 10, 10, mPaint);

		mPaint.setARGB(255, 0xff, 0xcc, 0xaa);

		// Draw letter circles
		for (int i = 0; i < mGame.getBoard().getSize(); i++) {
			int x = i % mGame.getBoard().getWidth();
			int y = i / mGame.getBoard().getWidth();
			float left = PADDING + mBoxSize * x;
			float top = PADDING + mBoxSize * y;

			if (((1L << i) & mHighlighted) == 0) {
				if (mGame.getBoard().isVocal(i)) {
					canvas.drawBitmap(mVocalLetter, left + 1, top + 1, mPaint);
				} else {
					canvas.drawBitmap(mConsonant, left + 1, top + 1, mPaint);
				}
			} else {
				canvas.drawBitmap(mOver, left + 1, top + 1, mPaint);
			}
		}

		mPaint.setARGB(255, 0, 0, 0);
		mPaint.setTextSize(mBoxSize - 24);
		mPaint.setTextAlign(Paint.Align.CENTER);

		mPaint.setTypeface(Typeface.MONOSPACE);
		for (int x = 0; x < mBoardWidth; x++) {
			for (int y = 0; y < mBoardWidth; y++) {
				final String txt = mGame.getBoard().elementAt(x, y);
				canvas.drawText(txt, PADDING + x * mBoxSize + mBoxSize / 2,
						(y + 1) * mBoxSize, mPaint);
			}
		}

	}

	private void drawTimer(Canvas canvas) {
		if (mTimeRemaining < 1000) {
			mPaint.setARGB(0xff, 0xd4, 0x00, 0x00);
		} else if (mTimeRemaining < 3000) {
			mPaint.setARGB(0xff, 0xff, 0x66, 0x00);
		} else {
			mPaint.setARGB(0xff, 0xff, 0xc8, 0x45);
		}

		mPaint.setStrokeWidth(PADDING * 4 / 3);
		canvas.drawLine(0, 0, mWidth * mTimeRemaining
				/ mGame.getMaxTimeRemaining(), 0, mPaint);

		int secRemaining = mTimeRemaining / 100;
		int mins = secRemaining / 60;
		int secs = secRemaining % 60;

		if (mTimeRemaining < 1000) {
			mPaint.setARGB(0xff, 0xd4, 0x00, 0x00);
		} else if (mTimeRemaining < 3000) {
			mPaint.setARGB(0xff, 0xff, 0x66, 0x00);
		} else {
			mPaint.setARGB(0xff, 0xff, 0xff, 0xff);
		}

		String time = "" + mins + ":";
		if (secs < 10) {
			time += "0" + (secRemaining % 60);
		} else {
			time += "" + (secRemaining % 60);
		}

		mPaint.setTextSize(PADDING * 2 / 3);
		canvas.drawText(time, mWidth / 2, PADDING * 2 / 3, mPaint);

	}

	private void drawScoreBoard(Canvas canvas, int left, int top, int width,
			int height) {
		mPaint.setARGB(255, 0xff, 0xcc, 0xaa);
		final RectF rect = new RectF(left, top, left + width, top + height);
		canvas.drawRoundRect(rect, 10, 10, mPaint);
		mPaint.setARGB(0xff, 0x28, 0x0b, 0x0b);
		mPaint.setStrokeWidth(2);
		canvas.drawLine(left, top + height / 2, left + width, top + height / 2,
				mPaint);

		canvas.drawLine(left + width / 2, top, left + width / 2, top + height,
				mPaint);

		mPaint.setTypeface(Typeface.SANS_SERIF);
		mPaint.setTextSize(PADDING);
		canvas.drawText(String.format("%d/%d  (%d%%)", mGame.getWordCount(),
				mGame.getMaxWordCount(), mGame.getLevelPercent()), left + width
				/ 4, top + height - PADDING / 4, mPaint);

		canvas.drawText(String.format("%d (%d%%)", mGame.getPoints(), mGame
				.getCurrentPercent()), left + width * 3 / 4, top + height
				- PADDING / 4, mPaint);

		mPaint.setTextSize(PADDING);
		canvas.drawText(getContext().getString(R.string.words), left + width
				/ 4, top + height / 2 - PADDING / 4, mPaint);
		canvas.drawText(getContext().getString(R.string.points), left + width
				* 3 / 4, top + height / 2 - PADDING / 4, mPaint);
		mPaint.setARGB(0xff, 0xff, 0xff, 0xff);
		mPaint.setTextSize(PADDING * 2 / 3);
		canvas.drawText(String.format("%s %d %s", getContext().getString(
				R.string.min_word_length), mGame.getMinWordLength(),
				getContext().getString(R.string.letters)), left + width / 2,
				top + height + PADDING, mPaint);
	}

	private void drawWordList(Canvas canvas, int left, int top, int bottom) {
		// draw current word
		mPaint.setTextSize(PADDING * 3 / 2);
		mPaint.setARGB(0xff, 0xff, 0xff, 0xff);
		if (mFingerTracker.getCurrentWord() != null) {
			canvas.drawText(mFingerTracker.getCurrentWord(), left, top
					+ PADDING, mPaint);
		}
		// draw words
		mPaint.setTextAlign(Align.LEFT);
		int pos = PADDING;
		ListIterator<String> li = mGame.listIterator();
		mPaint.setTextSize(PADDING * 2 / 3);

		while (li.hasNext()) {
			String w = li.next();
			int wlen = w.length() * PADDING * 2 / 3;
			if (pos + wlen > mWidth)
				break;
			if (mGame.isWord(w)) {
				mPaint.setARGB(0xff, 0xff, 0xff, 0xff);
			} else {
				mPaint.setARGB(0xff, 0xff, 0xc8, 0x45);
			}
			canvas.drawText(w, pos, mHeight - 4, mPaint);
			pos += wlen;
		}
	}

	private void drawScoreLandscape(Canvas canvas) {
		int textareatop = PADDING;
		int textareaheight = mHeight - 2 * PADDING;
		int textarealeft = 2 * PADDING + mGridSize;
		int textareawidth = mWidth - PADDING - textarealeft;
		drawScoreBoard(canvas, textarealeft, textareatop, textareawidth,
				textareaheight);
		drawWordList(canvas, textarealeft + textareawidth / 2,
				textareatop + 110, textareatop + textareaheight);

	}

	private void drawScorePortrait(Canvas canvas) {
		int textareatop = mGridSize + 3 * PADDING / 2;
		int textareaheight = mHeight / 10;
		int textarealeft = PADDING;
		int textareawidth = mWidth - 2 * PADDING;

		mPaint.setTypeface(Typeface.SANS_SERIF);
		drawScoreBoard(canvas, textarealeft, textareatop, textareawidth,
				textareaheight);

		drawWordList(canvas, mWidth / 2, mGridSize + 3 * PADDING + mHeight / 8,
				textareatop);

	}

	@Override
	public void onDraw(Canvas canvas) {
		// Log.d(TAG,"onDraw starts, canvas="+canvas);
		setDimensions(getMeasuredWidth(), getMeasuredHeight());

		canvas.drawRGB(0x28, 0x0b, 0x0b);

		if (mGame.getStatus() != Game.GameStatus.GAME_RUNNING)
			return;
		if (!mIsLoaded)
			return;
		drawBoard(canvas);
		drawTimer(canvas);

		if (mWidth > mHeight) {
			drawScoreLandscape(canvas);
		} else {
			drawScorePortrait(canvas);
		}

		// Log.d(TAG,"onDraw stops");
	}

	public void redraw() {
		mRedrawCount = REDRAW_FREQ;
		invalidate();
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// Log.d(TAG,"onTouchEvent() starts");
		if (mFingerTracker == null)
			return false;
		int action = event.getAction();
		switch (action) {
		case MotionEvent.ACTION_DOWN:
		case MotionEvent.ACTION_MOVE:
			mFingerTracker.touchScreen((int) event.getX(), (int) event.getY());
			break;
		case MotionEvent.ACTION_UP:
			mFingerTracker.release();
			break;
		}

		redraw();
		// Log.d(TAG,"onTouchEvent() ends");
		return true;
	}

	/*
	 * @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if
	 * (keyCode >= KeyEvent.KEYCODE_A && keyCode <= KeyEvent.KEYCODE_Z) {
	 * Log.d(TAG, "Letter Press:" + keyCode);
	 * mKeyboardTracker.processLetter(keyCode - KeyEvent.KEYCODE_A); } else if
	 * (keyCode == KeyEvent.KEYCODE_SPACE || keyCode == KeyEvent.KEYCODE_ENTER)
	 * { Log.d(TAG, "Enter or Space:" + keyCode); mKeyboardTracker.reset(); }
	 * else { Log.d(TAG, "Ignoring Key:" + keyCode); }
	 * 
	 * return false; }
	 */
	@Override
	public void tick(int time) {
		boolean doRedraw = false;

		mTimeRemaining = time;
		if (--mRedrawCount <= 0) {
			doRedraw = true;
		}
		if (doRedraw) {
			redraw();
		}
	}

}
